package com.ym521.ymandroidcrash

import android.content.Context
import android.os.Build
import android.os.Handler
import android.os.Looper
import com.ym521.ymandroidcrash.callback.OnActivityKillerCallback
import com.ym521.ymandroidcrash.core.*
import com.ym521.ymandroidcrash.core.api.ReflexAPi
import java.util.*


/**
 * Crash 防崩溃
 */
object YmAndroidCrach {
    private var sActivityKiller: OnActivityKillerCallback? = null
    private var sExceptionHandler: ExceptionHandler? = null
    private var sInstalled = false //标记位，避免重复安装卸载
    private var sIsSafeMode = false //安全模式状态

    @JvmStatic
    fun install(mContext: Context, exceptionHandler: ExceptionHandler) {
        if (sInstalled) {
            return
        }
        try {
            //解除 android P 反射限制
            ReflexAPi.unseal(mContext)
        } catch (throwable: Throwable) {
            throwable.printStackTrace()
        }
        sInstalled = true
        sExceptionHandler = exceptionHandler

        initActivityKiller()

        Thread.setDefaultUncaughtExceptionHandler { thread: Thread, throwable: Throwable? ->
            sExceptionHandler?.uncaughtExceptionHappened(
                thread,
                throwable
            )
            if (thread === Looper.getMainLooper().thread) {
                isChoreographerException(throwable)
                safeMode()
            }
        }
    }

    @JvmStatic
    fun isSafeMode(): Boolean {
        return sIsSafeMode
    }

    /**
     * 替换ActivityThread.mH.mCallback，实现拦截Activity生命周期，直接忽略生命周期的异常的话会导致黑屏，目前
     * 会调用ActivityManager的finishActivity结束掉生命周期抛出异常的Activity
     */
    private fun initActivityKiller() {
        //各版本android的ActivityManager获取方式，finishActivity的参数，token(binder对象)的获取不一样
        when (Build.VERSION.SDK_INT) {
            in 0 until 15 -> {
                sActivityKiller = ActivityKillerV15Callback()
            }
            in 15..20 -> {
                sActivityKiller = ActivityKillerV15Callback()
            }
            in 21..23 -> {
                sActivityKiller = ActivityKillerV21Callback()
            }
            in 24..25 -> {
                sActivityKiller = ActivityKillerV24Callback()
            }
            in 26..27 -> {
                sActivityKiller = ActivityKillerV26Callback()
            }
            else -> {
                sActivityKiller = ActivityKillerV28Callback()
            }
        }
        try {
            hookmH()
        } catch (e: Throwable) {
            e.printStackTrace()
        }
    }

    private const val LAUNCH_ACTIVITY = 100
    private const val PAUSE_ACTIVITY = 101
    private const val PAUSE_ACTIVITY_FINISHING = 102
    private const val STOP_ACTIVITY_HIDE = 104
    private const val RESUME_ACTIVITY = 107
    private const val DESTROY_ACTIVITY = 109
    private const val NEW_INTENT = 112
    private const val RELAUNCH_ACTIVITY = 126

    @Throws(Exception::class)
    private fun hookmH() {
        val activityThreadClass = Class.forName("android.app.ActivityThread")
        val activityThread =
            activityThreadClass.getDeclaredMethod("currentActivityThread").invoke(null)
        val mhField = activityThreadClass.getDeclaredField("mH")
        mhField.isAccessible = true
        val mhHandler = mhField[activityThread] as Handler
        val callbackField = Handler::class.java.getDeclaredField("mCallback")
        callbackField.isAccessible = true
        callbackField[mhHandler] = Handler.Callback { msg ->
            if (Build.VERSION.SDK_INT >= 28) { //android P 生命周期全部走这
                val EXECUTE_TRANSACTION = 159
                if (msg.what == EXECUTE_TRANSACTION) {
                    try {
                        mhHandler.handleMessage(msg)
                    } catch (throwable: Throwable) {
                        sActivityKiller!!.finishLaunchActivity(msg)
                        YmAndroidCrach.notifyException(throwable)
                    }
                    return@Callback true
                }
                return@Callback false
            }
            when (msg.what) {
                LAUNCH_ACTIVITY -> {
                    try {
                        mhHandler.handleMessage(msg)
                    } catch (throwable: Throwable) {
                        sActivityKiller!!.finishLaunchActivity(msg)
                        notifyException(throwable)
                    }
                    return@Callback true
                }
                RESUME_ACTIVITY -> {
                    try {
                        mhHandler.handleMessage(msg)
                    } catch (throwable: Throwable) {
                        sActivityKiller!!.finishResumeActivity(msg)
                        notifyException(throwable)
                    }
                    return@Callback true
                }
                PAUSE_ACTIVITY_FINISHING, PAUSE_ACTIVITY -> {
                    try {
                        mhHandler.handleMessage(msg)
                    } catch (throwable: Throwable) {
                        sActivityKiller!!.finishPauseActivity(msg)
                        notifyException(throwable)
                    }
                    return@Callback true
                }
                STOP_ACTIVITY_HIDE -> {
                    try {
                        mhHandler.handleMessage(msg)
                    } catch (throwable: Throwable) {
                        sActivityKiller!!.finishStopActivity(msg)
                        notifyException(throwable)
                    }
                    return@Callback true
                }
                DESTROY_ACTIVITY -> {
                    try {
                        mhHandler.handleMessage(msg)
                    } catch (throwable: Throwable) {
                        notifyException(throwable)
                    }
                    return@Callback true
                }
            }
            false
        }
    }

    private fun notifyException(throwable: Throwable) {
        if (sExceptionHandler == null) {
            return
        }
        if (isSafeMode()) {
            sExceptionHandler?.bandageExceptionHappened(throwable)
        } else {
            sExceptionHandler?.uncaughtExceptionHappened(Looper.getMainLooper().thread, throwable)
            safeMode()
        }
    }

    private fun safeMode() {
        sIsSafeMode = true
        sExceptionHandler?.enterSafeMode()
        while (true) {
            try {
                Looper.loop()
            } catch (throwable: Throwable) {
                isChoreographerException(throwable)
                sExceptionHandler?.bandageExceptionHappened(throwable)
            }
        }
    }

    /**
     * view measure layout draw时抛出异常会导致Choreographer挂掉
     *
     *
     * 建议直接杀死app。以后的版本会只关闭黑屏的Activity
     */
    private const val ELEMENT_CLASSNAME = "android.view.Choreographer"
    private const val ELEMENT_FILENAME = "Choreographer.java"
    private const val ELEMENT_METHODNAME = "doFrame"
    private fun isChoreographerException(throwable: Throwable?) {
        if (throwable == null || sExceptionHandler == null) {
            return
        }
        val elements = throwable.stackTrace ?: return
        val element = elements.reversed()
        for (i in element.indices) {
            if ((elements.size - i) > 20) {
                return
            }
            val element = elements[i]
            if (Objects.equals(ELEMENT_CLASSNAME, element.className)
                && Objects.equals(ELEMENT_FILENAME, element.fileName)
                && Objects.equals(ELEMENT_METHODNAME, element.methodName)
            ) {
                sExceptionHandler?.mayBeBlackScreen(throwable)
                return
            }
        }
    }

}